import { InsideErr, util } from "utils";
import { jwt } from "../../../utils";
import { AppToken } from "../../../const";
import type { BaseErr } from "utils";
import type { AliToken, AliUserInfo, DbUser, LoginUserInfo } from "../aliLoginService.type";
const db = uniCloud.database();
const dbCmd = db.command;
const collection = db.collection("baby-users-aliyun");

// 查询用户
async function searchUser(aliId: string): Promise<[BaseErr?, DbUser?]> {
    const aggregate = collection.aggregate();
    const $: any = dbCmd.aggregate;
    // 联表查询
    try {
        let matchRes = await aggregate
            .project({
                _id: 0,
                name: 1,
                id: 1,
                user_id: 1,
            })
            .match({
                id: dbCmd.eq(aliId),
            })
            .limit(1)
            .lookup({
                from: "baby-users",
                let: {
                    user_id: "$user_id",
                },
                pipeline: $.pipeline()
                    // @ts-ignore
                    .match(dbCmd.expr($.eq(["$_id", "$$user_id"])))
                    .done(),
                as: "userList",
            })
            .end();
        let { data } = matchRes || {};
        let dataArr = Array.isArray(data) ? data : [];
        let first: DbUser | undefined = dataArr[0];
        return [undefined, first];
    } catch (err: any) {
        return [new InsideErr(err), undefined];
    }
}

// 创建用户
async function createUser(
    tokenInfo: AliToken,
    userInfo: AliUserInfo
): Promise<[BaseErr?, LoginUserInfo?]> {
    // 使用事务
    // @ts-ignore
    const transaction = await db.startTransaction();
    try {
        let now = Date.now();
        // token 2小时
        // let token = jwt.sign({}, AppToken.secret, 60 * 60 * 2);
        // 先创建 用户
        let addUser = await transaction.collection("baby-users").add({
            createDate: now,
        });
        let aliUser = await transaction.collection("baby-users-aliyun").add({
            id: userInfo.id,
            createDate: now,
            name: userInfo.name || "",
            avatar: userInfo.avatar || "",
            phone: userInfo.phone || "",
            user_id: addUser.id,
        });

        await transaction.commit();
        // 2个都ok, 要返回token 了
        let resultTokenInfo: LoginUserInfo = {
            name: userInfo.name,
            app: {
                access_token: jwt.sign(
                    { id: addUser.id, ali: aliUser.id },
                    AppToken.secret,
                    60 * 60 * 2
                ),
                refresh_token: jwt.sign(
                    { id: addUser.id, ali: aliUser.id },
                    AppToken.secret,
                    60 * 60 * 24 * 3
                ),
                expires_in: 60 * 60 * 2 - 60 * 10,
            },
            ali: {
                access_token: tokenInfo.access_token,
                refresh_token: tokenInfo.refresh_token,
                expires_in: tokenInfo.expires_in,
            },
        };
        return [undefined, resultTokenInfo];
    } catch (error: any) {
        await transaction.rollback();
        return [new InsideErr(error), undefined];
    }
}
// 更新用户
function updateUserInfo(
    localData: DbUser,
    tokenInfo: AliToken,
    userInfo: AliUserInfo
): LoginUserInfo {
    let appUserId = localData.user_id;
    let aliId = localData.id;
    // 返回了jwt了
    let resultTokenInfo: LoginUserInfo = {
        name: userInfo.name,
        app: {
            access_token: jwt.sign({ id: appUserId, ali: aliId }, AppToken.secret, 60 * 60 * 2),
            refresh_token: jwt.sign(
                { id: appUserId, ali: aliId },
                AppToken.secret,
                60 * 60 * 24 * 3
            ),
            expires_in: 60 * 60 * 2 - 60 * 10,
        },
        ali: {
            access_token: tokenInfo.access_token,
            refresh_token: tokenInfo.refresh_token,
            expires_in: tokenInfo.expires_in,
        },
    };
    return resultTokenInfo;
}

// 数据库操作
async function dbHandle(tokenInfo: AliToken, userInfo: AliUserInfo): Promise<[BaseErr?, any?]> {
    let [localErr, localData] = await searchUser(userInfo.id);
    if (!util.nilValue(localErr)) {
        return [localErr, undefined];
    }
    // 判断数据
    if (util.nilValue(localData)) {
        // 要创建新用户
        return await createUser(tokenInfo, userInfo);
    } else {
        // 更新新用户
        let info = updateUserInfo(localData!, tokenInfo, userInfo);
        return [undefined, info];
    }
}

export { dbHandle };
